#include "unisphere.h"


/* max est le nombre de d'appelle a increase qu'il faut  */
/* pour changer de couleur, a voir commme un palier */

/* une méthode d'incrementation n'utilisant que */
/* le rouge */
void cl_increase_v1(Couleur* colorTop,double pasColor,int max)
{
/* times s'initialise a 1, */
/* sinon quand il y a une couleur max */
/* alors il y aura quand même un degradé */
  static int times=1;
  if (colorTop==NULL) { /* remise a 0 de times */
    times=1;
    return;
  }
  Couleur tmp=*colorTop;
  if (times<max)
    times++;
  else {
    tmp=cl(colorTop->R+max*pasColor,0.,0.);
    times=1;
  }
  *colorTop=tmp;
}

/* une méthode d'incrementation utilisant */
/* vert et rouge (comme les feux)*/
void cl_increase_v2(Couleur* colorTop,double pasColor,int max)
{
  static int times=1;
  if (colorTop==NULL) { /* remise a 0 de times */
    times=1;
    return;
  }
  Couleur tmp=*colorTop;
  if (times<max)
    times++;
  else {
    tmp=cl(colorTop->R+(pasColor*max),colorTop->G-(pasColor*max),0.);
    times=1;
  }
  *colorTop=tmp;
}

void cl_increase_v3(Couleur* colorTop,double pasColor,int max)
{
  static int times=1;
  if (colorTop==NULL) { /* remise a 0 de times */
    times=1;
    return;
  }
  Couleur tmp;
  int num=times%max; /* num comprit entre 0 et max-1 */
  /* int base=sqrt(max); */
  int base=(int) pow(max,1./3.);
 
  /* on exprime notre couleur dans la base base */
  /* le calcul de base est determiné par max,  */
  /* de maniere a ce qu'on puisse toucher toute les valeurs sur 3 chiffres */
  /* (et qu'on ne dépasse pas 3 chiffres) */
  tmp.R=num%base;
  num=num/base;
  tmp.G=num%base;
  num=num/base;
  tmp.B=num%base;
  num=num/base;
  *colorTop=tmp;
  times++;
}

/* un effet degradé de plus en plus serré */
/* mais toujours aussi puissant! */
void cl_increase_v4 (Couleur* colorTop,double pasColor,int max)
{
  static int times=1;
  static int count=0;
  static int color=0; /* color vaut 0 pour rouge,1 pour bleu et 2 pour vert */
  if (colorTop==NULL) { /* remise a 0 de times et autres */
    times=1;
    count=0;
    color=0;
    return;
  }

  if (times<max-count)
    times++;
  else
    {
      color+=1;
      color%=3;
      switch (color)
	{
	case 0:
	  *colorTop=cl(1.,0.,0.);
	  break;
	case 1:
	  *colorTop=cl(0.,1.,0.);
	  break;
	case 2:
	  *colorTop=cl(0.,0.,1.);
	  break;
	}
      count++;
      times=1;
    }
  return;
}

/* degradé de plus en plus serré, */
/* avec separation par ligne blanche de taille constante */
/* et d'un seule couleur! */
void cl_increase_v5 (Couleur* colorTop,double pasColor,int max)
{
  static int times=1;
  static int count=0;
  if (colorTop==NULL) { /* remise a 0 de times et autres */
    times=1;
    count=0;
    return;
  }
 /* si c'est du blanc, */
  /* on repasse au rouge */
  if (estBlanc((*colorTop)))
    {
/* on remet times a 1, */
/* et on incremente count quand on sort du blanc */
      times=1;
      count++;
      *colorTop=cl((double)count*pasColor*max,0.,0.);
    }
  /* sinon on test si garde la couleur actuelle */
  else if (times<max-count) 
    times++;
  /* sinon on test si il faut passer au blanc */
  else 
    {
      (*colorTop)=cl(1.,1.,1.);
    }
  return;
}

/* degradé de plus en plus serré, */
/* avec separation par ligne blanche de taille constante */
/* et d'un seule couleur! */
void cl_increase_v6 (Couleur* colorTop,double pasColor,int max)
{
  static int times=1;
  static int count=0;
  if (colorTop==NULL) { /* remise a 0 de times et autres */
    times=1;
    count=0;
    return;
  }
 /* si c'est du blanc, */
  /* on repasse au rouge */
  if (estBlanc((*colorTop)))
    {
/* on remet times a 1, */
/* et on incremente count quand on sort du blanc */
      times=1;
      count++;
      *colorTop=cl(1.-(double)count*pasColor*max,(double)count*pasColor*max,0.);
    }
  /* sinon on test si garde la couleur actuelle */
  else if (times<max-count) 
    times++;
  /* sinon on test si il faut passer au blanc */
  else 
    {
      (*colorTop)=cl(1.,1.,1.);
    }
  return;
}



Couleur cl_init_v1()
{
  return cl(0.,0.,0.); /* on commence avec du noir */
  return cl(0.1,0.,0.); /* on commence avec du presque noir */
}

Couleur cl_init_v2()
{
  /* return cl(0.,1.,0.); /\* on commence avec du vert *\/ */
  return cl(0.,0.8,0.2); /* on commence avec du presque vert */
}

Couleur cl_init_v3()
{
  return cl(0.,0.,0.); /* on commence avec du noir */
}

Couleur cl_init_v4()
{
  return cl(1.,0.,0.); /* on commence avec du rouge */
}
Couleur cl_init_v5()
{
  return cl(0.1,0.,0.);
}

Couleur cl_init_v6()
{
  return cl(0.9,0.1,0.);
}


void drawUniSphere (Point c,double R, int nbcoup,
		    double SALPHA,double SBETA,
		    int max,
		    Couleur (*cl_init)(),
		    void (*cl_increase)(Couleur* colorTop,double pasColor,int max))
{
  /* sauvegarde de la matrice */
  /* pour la mouse */

  glPushMatrix();
/* changement du repère */
  /* on commence par mettre le centre en 0,0,0 */
  glTranslatef(c.x,c.y,c.z);

  glRotatef(SALPHA,0,0,1);
  /* en effet si SBETA vaut 90, on bouge pas */
  /* de plus notre angle est orienté a l'envers =) */
  glRotatef(360-(SBETA-90.),0,1,0);

  /* le centre est en 0,0,0, donc  */
  /* les points sont considérés comme des vecteurs */
  /* (en particulier on ajoute plus les coordonnées du  */
  /* centre) */
  double x,y,z;
  double alpha=0.;
  double beta=-90.;
/* le remplissage se fait de bas en haut */
  Couleur colorBottom=cl_init();
/* couleur de l'étage d'au dessus */
  Couleur colorTop=cl_init();

  double r;
  Point p1,p2,p3,p4;

/* on initialise colorTop et non colorBottom  */
/* car le premier tour dans la boucle on ne dessine pas */

  double pasAlpha=360./(double)nbcoup;
  double pasBeta=180./(double)nbcoup;
  double pasColor=1./(double)nbcoup;
/* la couleur de l'étage d'en dessous */

  Point** matrice=newMatricePoint(nbcoup+1);

  int i,j;
  for (i=0;i<nbcoup+1;i++)
    {
      /* le rayon du sous cercle */
      r=R*cos(rad(beta));
      /* le sous cercle qu'on trace */
      z=sin(rad(beta))*R;

      
      for (j=0;j<nbcoup+1;j++)
	{
	  /* cercle des x par rapport aux y */
	  x=cos(rad(alpha))*r;
	  y=sin(rad(alpha))*r;
	  alpha+=pasAlpha;

	  matrice[i][j]=pt(x,y,z);
	  /* si ce n'est pas le premier tour, on dessine des quad */
	  if (i!=0)
	    {
	      if (j>0)
		{
		  glBegin(GL_QUADS);
/* on traite 2 points d'un étage inferieur */
		  chooseCouleur(colorBottom);

		  p1=matrice[i-1][j];
		  glVertex3f(p1.x,p1.y,p1.z);

		  p2=matrice[i-1][j-1];
		  glVertex3f(p2.x,p2.y,p2.z);
/* puis 2 point de l'étage superieur */
		  chooseCouleur(colorTop);
		  p3=matrice[i][j-1];
		  glVertex3f(p3.x,p3.y,p3.z);

		  p4=matrice[i][j];
		  glVertex3f(p4.x,p4.y,p4.z);
		  glEnd();
		}
	    }
	}
/* on monte d'un étage */
      colorBottom=colorTop;
      cl_increase(&colorTop,pasColor,max);

      alpha=0.;
      beta+=pasBeta;
    }
  libererMatricePoint(matrice,nbcoup+1);
/*  remise a 0 de times, */
/* la variable statique */
  cl_increase(NULL,0.,0);
  /* on restaure l'ancienne matrice */
  glPopMatrix();
  return;
}


void drawUniTexSphere (Point c,double R, int nbcoup,
		       double SALPHA,double SBETA,
		       int maxRepeat)
{
  chooseColor(1.,1.,1.);
/* sauvegarde de la matrice */
  /* pour la mouse */

  glPushMatrix();
/* changement du repère */
  /* on commence par mettre le centre en 0,0,0 */
  glTranslatef(c.x,c.y,c.z);

  glRotatef(SALPHA,0,0,1);
  /* en effet si SBETA vaut 90, on bouge pas */
  /* de plus notre angle est orienté a l'envers =) */
  glRotatef(360-(SBETA-90.),0,1,0);
  
  /* cette rotation place le centre de l'image au top */
  /* de la sphere */
  glRotatef(90,0,1,0);

  /* le centre est en 0,0,0, donc  */
  /* les points sont considérés comme des vecteurs */
  /* (en particulier on ajoute plus les coordonnées du  */
  /* centre) */
  double x,y,z;
  double alpha=0.;
/* le remplissage se fait de bas en haut */
  double beta=-90.;
  double r;
  Point p1,p2,p3,p4;
  if (maxRepeat==0)
    maxRepeat=1;
  int repeat=nbcoup/maxRepeat;

  double pasAlpha=360./(double)nbcoup;
  double pasBeta=180./(double)nbcoup;

  Point** matrice=newMatricePoint(nbcoup+1);

  int i,j;
  for (i=0;i<nbcoup+1;i++)
    {
      /* le rayon du sous cercle */
      r=R*cos(rad(beta));
      /* le sous cercle qu'on trace */
      z=sin(rad(beta))*R;

      
      for (j=0;j<nbcoup+1;j++)
	{
	  /* cercle des x par rapport aux y */
	  x=cos(rad(alpha))*r;
	  y=sin(rad(alpha))*r;
	  alpha+=pasAlpha;

	  matrice[i][j]=pt(x,y,z);
	  /* si ce n'est pas le premier tour, on dessine des quad */
	  if (i!=0)
	    {
	      if (j>0)
		{
		  glBegin(GL_QUADS);
/* on traite 2 points d'un étage inferieur */

		  p1=matrice[i-1][j];
		  glTexCoord2d(((double)i-1.)/(double)((nbcoup+1.)),(double)j/(double)(repeat));
		  glVertex3f(p1.x,p1.y,p1.z);

		  p2=matrice[i-1][j-1];
		  glTexCoord2d(((double)i-1.)/(double)(nbcoup+1.),((double)j-1.)/(double)(repeat));
		  glVertex3f(p2.x,p2.y,p2.z);
/* puis 2 point de l'étage superieur */
		  p3=matrice[i][j-1];
		  glTexCoord2d((double)i/(double)(nbcoup+1.),((double)j-1.)/(double)(repeat));
		  glVertex3f(p3.x,p3.y,p3.z);

		  p4=matrice[i][j];
		  glTexCoord2d((double)i/(double)(nbcoup+1.),(double)j/(double)(repeat));
		  glVertex3f(p4.x,p4.y,p4.z);
		  glEnd();
		}
	    }
	}
      alpha=0.;
      beta+=pasBeta;
    }
  libererMatricePoint(matrice,nbcoup+1);


  /* on restaure l'ancienne matrice */
  glPopMatrix();
  return;
}
